﻿// License: The MIT License (MIT) Copyright (c) 2011 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.IO;
using System.Windows;
using System.Windows.Controls;

namespace GrooveSharp
{
    /// <summary>
    /// This GUI class implements the library (treeview / folder structure to add tracks from)
    /// </summary>
    public partial class MusicLibrary : UserControl
    {

        private class TreeTag
        {
            public int Id { get; set; }
            public string FileOrFolderName { get; set; }
            public bool IsFolder { get; set; }
        }

        public MusicLibrary()
        {
            InitializeComponent();
        }

        // Cookbook methods to implement an event
        // http://www.codeproject.com/KB/WPF/WPF_CustomerControl.aspx#
        public static readonly RoutedEvent addTrackEvent =
                  EventManager.RegisterRoutedEvent("AddTrack", RoutingStrategy.Bubble,
                    typeof(RoutedEventHandler), typeof(MusicLibrary));

        public event RoutedEventHandler AddTrack
        {
            add { AddHandler(addTrackEvent, value); }
            remove { RemoveHandler(addTrackEvent, value); }
        }

        // Implementation

        private void AddDBListToTree(ItemCollection items, IEnumerable<LibraryItem> dbItems, int index)
        {
            LibraryItem previous = new LibraryItem();
            foreach (LibraryItem dbItem in dbItems)
            {
                if (index >= dbItem.Items.Count)
                {
                    return;
                }

                if (previous.Items.Count == 0 || previous.Items[index] != dbItem.Items[index])
                {
                    // Construct a new one, either with complete info (if on lowest level), or empty to add subnodes later
                    bool hasSubNodes = index < dbItem.Items.Count - 1;
                    TreeViewItem item = new TreeViewItem()
                        {
                            Header = dbItem.Items[index],
                            Tag = hasSubNodes
                                ? new TreeTag()
                                : new TreeTag()
                                    {
                                        Id = dbItem.TrackId,
                                        FileOrFolderName = dbItem.FileName,
                                        IsFolder = false
                                    }
                        };
                    items.Add(item);
                    AddDBListToTree(item.Items,
                        from p in dbItems where p.Items.Count > 0 && p.Items[index] == dbItem.Items[index] select p,
                        index + 1);
                }
                previous = dbItem;
            }
        }

        private void AddFolderToTree(ItemCollection items, String folderName)
        {
            bool hasSub = false;
            foreach (String subFolder in Directory.GetDirectories(folderName))
            {
                TreeViewItem item = new TreeViewItem()
                {
                    Header = System.IO.Path.GetFileName(subFolder),
                    Tag = new TreeTag()
                    {
                        FileOrFolderName = subFolder,
                        IsFolder = true
                    }
                };
                items.Add(item);
                AddFolderToTree(item.Items, subFolder);
                hasSub = true;
            }
            if (!hasSub)
            {
                foreach (String file in Directory.GetFiles(folderName, "*.mp3"))
                {
                    TreeViewItem item = new TreeViewItem()
                    {
                        Header = System.IO.Path.GetFileNameWithoutExtension(file),
                        Tag = new TreeTag()
                        {
                            FileOrFolderName = file,
                            IsFolder = false
                        }
                    };
                    items.Add(item);
                }
            }
        }

        private void AddFromDB()
        {
            var items = Db.Connection().Select<LibraryItem>(@"
select a.artist_name,m.album_title,t.track_title,t.track_id,t.folder_name,t.file_name
from tracks t
    join albums m on t.album_id=m.album_id
    join artists a on a.artist_id=t.artist_id
order by artist_name,album_title,t.disc_number,t.track_number;
                ");

            AddDBListToTree(treeViewCollection.Items, items, 0);
        }
        private void AddFromYAT()
        {
            var items = Db.Connection().Select<LibraryItem>(@"
select t.track_year,a.artist_name,m.album_title,t.track_title,t.track_id,t.folder_name,t.file_name
from tracks t
    join albums m on t.album_id=m.album_id
    join artists a on a.artist_id=t.artist_id
order by t.track_year,artist_name,album_title,t.disc_number,t.track_number;
                ");

            AddDBListToTree(treeViewCollection.Items, items, 0);
        }

        public void LoadCollectionIfEmpty()
        {
            if (treeViewCollection.Items.IsEmpty)
            {
                AddFromDB();
                radioArtistAlbumTrack.IsChecked = true;

                if (treeViewCollection.Items.IsEmpty)
                {
                    radioFolder.IsChecked = true;
                    AddFolderToTree(treeViewCollection.Items, App.GrooveFolder());
                }
                else
                {
                    radioArtistAlbumTrack.IsEnabled = true;
                    radioYearAlbumTrack.IsEnabled = true;
                }
            }
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            if (treeViewCollection.SelectedItem != null)
            {
                RaiseEvent(new RoutedEventArgs(addTrackEvent));
            }
        }

        private IList<QueuedTrack> SelectedTracks(TreeViewItem item)
        {
            var result = new List<QueuedTrack>();
            if (item.Tag is TreeTag)
            {
                TreeTag tag = item.Tag as TreeTag;

                if (tag.IsFolder)
                {
                    // A filesystem folder, add all MP3 files in folder
                    var list = Directory.GetFiles(tag.FileOrFolderName, "*.mp3");
                    result.AddRange(from p in list select new QueuedTrack() { FileName = p });
                }

                if (item.Items.Count > 0)
                {
                    // Recursively add all subnodes (either from file-system, or DB based)
                    foreach (TreeViewItem subItem in item.Items)
                    {
                        result.AddRange(SelectedTracks(subItem));
                    }
                }
                else
                {
                    // Just add the selected item, can be from filesystem or DB based
                    result.Add(new QueuedTrack() { Id = tag.Id, FileName = tag.FileOrFolderName });
                }
            }
            return result;
        }


        public IList<QueuedTrack> SelectedTracks()
        {
            return treeViewCollection.SelectedItem != null && treeViewCollection.SelectedItem is TreeViewItem
                ?  SelectedTracks(treeViewCollection.SelectedItem as TreeViewItem)
                : new List<QueuedTrack>()
                ;
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            // Scan folder and add all artists/tracks from default folder
            //new ReadFromFolders().Read(App.MusicFolder());

            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                new FolderScanner().Read(App.GrooveFolder());
            };
            worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
            {
                treeViewCollection.Items.Clear();

                radioArtistAlbumTrack.IsEnabled = true;
                radioYearAlbumTrack.IsEnabled = true;
                radioArtistAlbumTrack.IsChecked = true;

                AddFromDB();
            };
            worker.RunWorkerAsync();

        }


        private bool isChecked(RadioButton r)
        {
            return r.IsChecked.HasValue && (bool) r.IsChecked.Value;
        }

        private void radioTreeChecked(object sender, RoutedEventArgs e)
        {
            treeViewCollection.Items.Clear();
            if (isChecked(radioFolder))
            {
                AddFolderToTree(treeViewCollection.Items, App.GrooveFolder());
            }
            else if (isChecked(radioArtistAlbumTrack))
            {
                AddFromDB();
            }
            else if (isChecked(radioYearAlbumTrack))
            {
                AddFromYAT();
            }
        }

    }

}
